package com.central.oauth.granter;

import com.central.oauth2.common.token.MobileCodeAuthenticationToken;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 自定义第 4 种认证方式，手机短信登录
 *
 * @author ly
 * @email 664162337@qq.com
 * @date 2020/10/10 14:07
 */
public class MobileCodeGranter extends AbstractTokenGranter {

    private static final String GRANT_TYPE = "mobile_code";

    private final AuthenticationManager authenticationManager;

    public MobileCodeGranter(AuthenticationManager authenticationManager,
                             AuthorizationServerTokenServices tokenServices,
                             ClientDetailsService clientDetailsService,
                             OAuth2RequestFactory requestFactory) {
        super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
        this.authenticationManager = authenticationManager;
    }

    @Override
    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
        Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());
        String mobile = parameters.get("mobile");
        String validCode = parameters.get("validCode");

        // 组装认证需要用的数据
        Authentication userAuth = new MobileCodeAuthenticationToken(mobile, validCode);
        ((AbstractAuthenticationToken) userAuth).setDetails(parameters);
        // 调用认证方法. 会交给 ProviderManager 调用 实现了 AuthenticationProvider 接口的方法
        // com.central.oauth.mobile.MobileCodeAuthenticationProvider
        userAuth = authenticationManager.authenticate(userAuth);
        if (userAuth == null || !userAuth.isAuthenticated()) {
            throw new InvalidGrantException("Could not authenticate mobilith code: " + mobile);
        }

        OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
        return new OAuth2Authentication(storedOAuth2Request, userAuth);
    }
}
